home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Graphics⁄Sound / RTrace-1.0-src / macstuff.c < prev    next >
Text File  |  1992-10-27  |  87KB  |  2,503 lines

  1. /*****************************************************************************\
  2. * macstuff.c                                                                  *
  3. *                                                                             *
  4. * This file contains code which is specific to the Macintosh.  It contains    *
  5. * procedures which initialize rtrace as a macintosh application.              *
  6. \*****************************************************************************/
  7.  
  8. #include "rtresources.h"
  9. #include "defs.h"
  10. #include "extern.h"
  11. #include "mactypes.h"
  12. #include "macerrors.h"
  13. #include <setjmp.h>
  14. #include <Retrace.h>
  15. #include <GestaltEqu.h>
  16. #include <Folders.h>
  17. #include <AppleEvents.h>
  18. #include <Movies.h>
  19.  
  20. /* Globals */
  21. PicHandle        down_arrow_picture;        /* Pictures used for popup menus */
  22. PicHandle        down_arrow_picture_grayed;
  23. short            current_line;            /* used to trace the line being drawn */
  24. Rect            drag_window_rect;        /* the area in which windows may be dragged */
  25. WindowPtr        image_window;            /* the image window data structures */
  26. CWindowRecord    image_window_rec;
  27. CGrafPort         image_port_rec;            /* offscreen port which contains the image */
  28. CGrafPtr          image_port = &image_port_rec;
  29. MenuHandle        apple_menu;                /* handles to pulldown menus */
  30. MenuHandle        file_menu;
  31. MenuHandle        edit_menu;
  32. MenuHandle        windows_menu;
  33. long            before_time;            /* used to time processes */
  34. double            t;                        /* current value of t during animation */
  35.  
  36. /*    Think C likes all caps for routines in converted .o files. */
  37.  
  38. #ifdef    THINK_C
  39. #define    OpenStdCompression    OPENSTDCOMPRESSION
  40. #endif
  41.  
  42. #include "StdCompression.h"
  43.  
  44.  
  45. /* externals */
  46.  
  47. extern ComponentInstance    ci;                /* returned from OpenStdCompression(), used in
  48.                                              *   QuickTime movie save dialog.
  49.                                              */
  50. extern MenuHandle    save_anim_file_type_menu;
  51. extern long            image_width;            /* size of the image to be generated */
  52. extern long            image_height;
  53. extern Boolean        show_image_rendering;    /* TRUE if we show the image in a window */
  54. extern Boolean        keep_image_in_memory;    /* TRUE if we keep a pixmap in memory */
  55. extern short        save_file_type_menu_selection;
  56. extern short        save_anim_file_type_menu_selection;
  57. extern char            last_log_line[];        /* The last line in the log text */
  58. extern WindowPtr     log_window;
  59. extern FILE            *stderr_file;            /* file to which stderr is redirected */
  60. extern fpos_t        current_stderr_read_pos;/* position we're reading in stderr */
  61. extern Boolean        allow_background_tasks;    /* TRUE if we handle events and give time to
  62.                                                 background processed while rendering */
  63. extern Boolean        show_status_window_flag;/* TRUE if the status dialog is shown each render */
  64. extern Boolean        show_about_window_flag;    /* TRUE if the about window is shown at startup */
  65. extern Boolean        hide_options_window_flag;/* TRUE if the options dialog is hidden each render */
  66. extern long            time_between_events;    /* number of ticks between calls to WaitNextEvent */
  67. extern DialogPtr    options_dialog;            /* the options dialog */
  68. extern DialogPtr    preferences_dialog;        /* the preferences dialog */
  69. extern DialogPtr    animation_dialog;        /* the animation dialog */
  70. extern DialogPtr     status_dialog;            /* the status dialog */
  71. extern DialogPtr    cancel_dialog;            /* the Cancel dialog */
  72. extern DialogPtr    abort_render_dialog;    /* the Abort Render dialog */
  73. extern DialogPtr    prompt_save_dialog;        /* the Prompt To Save dialog */
  74. extern ControlHandle render_button_handle;    /* handle to the Render button */
  75. extern ControlHandle animation_okay_button_handle;/* handle to the Okay button in animation */
  76. extern ControlHandle preferences_okay_button_handle;/* handle to the Okay button in preferences */
  77. extern ControlHandle animate_checkbox;        /* handle to the animate checkbox in animation */
  78. extern short        blessed_folder_wd_id;    /* Working Directory refnum of blessed folder */
  79. extern short        rtrace_wd_id;            /* Working Directory refnum of RTrace folder */
  80.  
  81. Boolean    fpu_available;                    /* TRUE if the machine has a math coprocessor */
  82. Boolean    mc68020_available;                /* TRUE if the machine has a 68020 or better */
  83. Boolean    f8bit_QD_available;                /* TRUE if 8-bit QuickDraw is available */
  84. Boolean    f32bit_QD_available;            /* TRUE if 32-bit QuickDraw is available */
  85. Boolean    find_folder_available;            /* TRUE if FindFolder is available */
  86. Boolean    notification_manager_available;    /* TRUE if the Notification Manager is available */
  87. Boolean    apple_events_available;            /* TRUE if Apple Events are available */
  88. Boolean    quicktime_available;            /* TRUE if QuickTime is available */
  89. Boolean    dither_copy_available;            /* TRUE if QuickDraw supports dithered copying */
  90.  
  91. Boolean    rendering;                        /* TRUE while we are rendering */
  92. Boolean    do_enclose;                        /* TRUE if ray_trace() should enclose */
  93. Boolean is_offscreen_port = FALSE;        /* TRUE when there is an offscreen CGrafPort */
  94. Boolean    image_complete = FALSE;            /* TRUE if the image is completely rendered */
  95. Boolean get_another_event = FALSE;        /* TRUE if we're due to get another event */
  96. Boolean vbl_installed = FALSE;            /* TRUE if the VBL event task is installed */
  97. Boolean scene_in_memory = FALSE;        /* TRUE if the scene for the current file is in memory */
  98. Boolean rendering_same_file = FALSE;    /* TRUE if the file is same as last render */
  99. Boolean    texture_mode_changed = TRUE;    /* TRUE if the texture mode is different than last render */
  100. Boolean notification_installed = FALSE;    /* TRUE when a notification is installed */
  101. Boolean    in_background = FALSE;            /* TRUE when the app is in the background */
  102. Boolean    scene_file_open = FALSE;        /* TRUE when the scene file is open */
  103. Boolean    picture_file_open = FALSE;        /* TRUE when the picture file is open */
  104. Boolean    starting_up = TRUE;                /* TRUE if we're still starting up */
  105. Boolean    image_saved = TRUE;                /* TRUE if the image has been saved since last modification */
  106.  
  107. short   display_depth;                  /* Actual display depth in bits: 1, 4, 8, or 32 bits */
  108.  
  109. NMRec    notification;                    /* A notification */
  110. Handle    notification_icon;                /* Handle to the notification icon */
  111.  
  112. long    number_noncluster_objects;        /* number of objects which are not cluster objects */
  113. long    total_time;                        /* Used to time rendering */
  114. jmp_buf    environment;                    /* Used to store environment to restore on error */
  115.  
  116. short    sff_file_vrefnum = 0;            /* The volume refnum of the sff file directory */
  117. long    num_lights, num_surfaces;        /* The number of lights and surfaces in this scene */
  118. long    frames;                            /* The number of frames in the animation sequence */
  119.  
  120. /* rtrace data */
  121. extern short int previous_repetitions;
  122. short    SCREEN_SIZE_X_MAX;
  123. short    SCREEN_SIZE_Y_MAX;
  124. short    OBJECTS_MAX = 10000;    /* default */
  125.  
  126. char    sff_filename[200];        /* pathname of file to render */
  127.  
  128. /* Prototypes */
  129. extern void init_mac(void);
  130. void init_mgrs(void);
  131. void init_menus(void);
  132. void do_mouse_down(EventRecord *event);
  133. void handle_open(FSSpec *file_spec);
  134. void do_menu(long command);
  135. void process_mac_event(void);
  136. void debug_exit (void);
  137. void handle_update_event(WindowPtr the_window);
  138. void dispose_offscreen_port (void);
  139. void create_offscreen_grafport(Rect *bounds_rect);
  140. void do_mac(void);
  141. void handle_save(void);
  142. void do_edit(short item);
  143. pascal void scroll_action_proc(void);
  144. pascal void set_event_flag(void);
  145. void remove_get_event_vbl(void);
  146. void install_get_event_vbl(void);
  147. void handle_key_down(EventRecord *event);
  148. void handle_multifinder_event(EventRecord *event);
  149. Boolean handle_dialog_event(EventRecord *event);
  150. pascal OSErr open_app_ae_handler(AppleEvent *aevent, AppleEvent *reply, long handler_refcon);
  151. pascal OSErr quit_app_ae_handler(AppleEvent *aevent, AppleEvent *reply, long handler_refcon);
  152. pascal OSErr open_docs_ae_handler(AppleEvent *aevent, AppleEvent *reply, long handler_refcon);
  153. void init_apple_events(void);
  154. void handle_high_level_event(EventRecord *event);
  155. OSErr got_required_parameters(AppleEvent *aevent);
  156. Boolean prepare_to_terminate(void);
  157.  
  158.  
  159. /* External Prototypes */
  160. extern void init_alert_dialogs(void);
  161. extern Boolean open_sff_file(char *filename);
  162. extern void init_dialogs(void);
  163. extern void show_about_dialog(void);
  164. extern void add_parameter(params_struct *params, char *param);
  165. extern void tc_ray_trace (void);
  166. extern void get_parameters (int, char_ptr[]);
  167. extern void get_scene (void);
  168. extern void ray_trace (void);
  169. extern void do_preferences_dialog(void);
  170. extern void ray_trace_sff(void);
  171. extern pascal Boolean save_image_filter (DialogPtr the_dialog, EventRecord *event,
  172.                                             int *the_item);
  173. extern char *get_save_filename (void);
  174. extern void post_render(Boolean natural);
  175. extern void do_stdout_check(void);
  176. extern void setup_log_window(void);
  177. extern void update_log_window (void);
  178. extern void handle_log_click(Point where);
  179. extern void save_pict_file(SFReply    *my_reply);
  180. extern void save_ppm_file(SFReply *my_reply);
  181. extern void save_quicktime_movie(SFReply *my_reply);
  182. extern void save_pict_files(SFReply *my_reply);
  183. extern void free_all(void);
  184. extern void handle_log_window_zoom(Point where, short part_code);
  185. extern void grow_log_window(Point where);
  186. extern void update_scroll_bar(void);
  187. extern void update_scroll_bar_with_active(Boolean active);
  188. extern void mac_halt(void);
  189. extern void show_options_dialog(Boolean bring_to_front);
  190. extern void hide_options_dialog(void);
  191. extern void show_animation_dialog(Boolean bring_to_front);
  192. extern void hide_animation_dialog(void);
  193. extern void show_log_window(Boolean bring_to_front);
  194. extern void hide_log_window(void);
  195. extern void show_status_dialog(Boolean bring_to_front);
  196. extern void hide_status_dialog(void);
  197. extern void handle_animation_selection(short item_hit);
  198. extern void handle_options_selection(short item_hit);
  199. extern void update_render_button(void);
  200. extern void init_mac_alloc(void);
  201. extern void preprocess_sff_file(long *num_lights, long *num_surfaces, long *num_objects);
  202. extern void generate_params(params_struct *params);
  203. extern void set_status_image_data_size(long image_size);
  204. extern void add_line_to_log_window (char *line);
  205. extern void set_status_num_objects(long num_objects);
  206. extern void get_preferences(void);
  207. extern void write_preferences(void);
  208. extern void place_window (WindowPtr window, Rect *bounds);
  209. extern void set_dialog_real(DialogPtr dialog, short item, real number);
  210. extern void get_system_info(void);
  211. extern void show_image_window(Boolean bring_to_front);
  212. extern void hide_image_window(void);
  213. extern void get_animation_info(real *tstart, real *tend, long *frames);
  214. extern Boolean find_variable_value (char *var_name, double *value);
  215. extern void setup_frame(void);
  216. extern void setup_temp_folder(void);
  217. extern void delete_temp_files(Boolean movie_too);
  218. extern short make_working_directory(short vrefnum, long dir_id);
  219. extern void log_window_resized(void);
  220. extern void show_preferences_dialog(void);
  221. extern void handle_preferences_selection(short item_hit);
  222.  
  223.  
  224.  
  225. /*****************************************************************************\
  226. * procedure do_mac                                                            *
  227. *                                                                             *
  228. * Purpose: This procedure initializes the mac application, and then goes off  *
  229. *          to the event loop.                                                 *
  230. *                                                                             *
  231. * Created by: Greg Ferrar                                                     *
  232. * Created on: August 21, 1992                                                 *
  233. * Modified:                                                                   *
  234. \*****************************************************************************/
  235.  
  236. void do_mac(void)
  237. {
  238.  
  239.     long    i;
  240.     Str255    pict_filename;
  241.     char    ppm_filename[255];
  242.  
  243. DB(" before init_mac ");
  244.     
  245.      /* Initialize */
  246.     init_mac();
  247.  
  248. DB(" after init_mac ");
  249.  
  250.     /* We're no longer starting up */
  251.     starting_up = FALSE;
  252.  
  253.     /* Put up the about dialog as an intro, if prefs say to */
  254.     if (show_about_window_flag)
  255.         show_about_dialog();
  256.  
  257.     /* If there is an error later, this is where we want to return to.  The
  258.         error handler will return here by calling longjmp() */
  259.     setjmp(environment);
  260.     
  261.     /* Not rendering now */
  262.     rendering = FALSE;
  263.         
  264.     /* Go to the event loop, never return */
  265.     process_mac_event();
  266.     
  267. }
  268.  
  269.  
  270.  
  271. /*****************************************************************************\
  272. * procedure init_mac                                                          *
  273. *                                                                             *
  274. * Purpose: This procedure initializes rtrace as a mac program, and sets up    *
  275. *          the menus.                                                         *
  276. *                                                                             *
  277. * Created by: Greg Ferrar                                                     *
  278. * Created on: August 21, 1992                                                 *
  279. * Modified:                                                                   *
  280. *   Reid Judd    Oct. 18, '92    Fix bug in QuickTime movie output. Init the   *
  281. *                                  ComponentInstance for OpenStdCompression()  *
  282. *                                  before EnterMovies()                          *
  283. \*****************************************************************************/
  284.  
  285. void init_mac()
  286. {
  287.  
  288.     Rect    image_window_frame = {0, 0, 256, 256};
  289.     Str255    volume_name;
  290.     short    rtrace_vrefnum;
  291.     long    rtrace_dirid;
  292.     short    error;
  293.     short    attribs;
  294.     WDPBRec    pb;
  295.     
  296.      /* initialize the toolbox */
  297.     init_mgrs();
  298.     
  299.     /* Initialize the alert dialogs in case we need them for errors */
  300.     init_alert_dialogs();
  301.  
  302.     /* find what kind of system we have here */
  303.     get_system_info();
  304.  
  305.     /* initialize the menus */
  306.     init_menus();
  307.      
  308.     /* Initialize the dialogs */
  309.     init_dialogs();
  310.  
  311.     /* Initialize the apple events handlers, if apple events are available */
  312.     if (apple_events_available)
  313.         init_apple_events();
  314.          
  315.     /* Initialize QuickTime, if we have it */
  316.     if (quicktime_available)
  317.     {
  318.         ci = OpenStdCompression();
  319.         if (ci == NULL) 
  320.             terminal_string_error("Can't initialize QuickTime Standard Compression.");        
  321.                  
  322.         error = EnterMovies();
  323.         if (error) 
  324.             terminal_error(error);  
  325.     }
  326.     
  327.     /* If there's no QuickTime, don't let user save as QT movie */
  328.     else
  329.         DisableItem(save_anim_file_type_menu, 2);
  330.     
  331.     /* If it is possible to have an Image Window, create it */
  332.     if (f8bit_QD_available)
  333.         image_window = NewCWindow (&image_window_rec, &image_window_frame, "\pImage",
  334.                                     FALSE, 0, (WindowPtr) -1L, TRUE, 0);
  335.     else
  336.         /* Dim the Show Image Window menu item */
  337.         DisableItem (windows_menu, SHOW_IMAGE_ITEM);
  338.  
  339.     /* Get the down arrow pictures for the popup menus */
  340.     down_arrow_picture = (PicHandle) GetResource ('PICT', DOWN_ARROW_PICT);
  341.     down_arrow_picture_grayed = (PicHandle) GetResource ('PICT', DOWN_ARROW_PICT_GRAYED);
  342.  
  343.     /* Get the small icon for the notification */
  344.     notification_icon = GetResource ('ICN#', NOTIFICATION_ICON);
  345.     attribs = GetResAttrs (notification_icon);
  346.     SetResAttrs (notification_icon, attribs & (!resPurgeable));
  347.     LoadResource(notification_icon);
  348.  
  349.     /* Set up window dragging region */
  350.     drag_window_rect = screenBits.bounds;
  351.     InsetRect (&drag_window_rect, 4, 4);
  352.  
  353.     /* Init the memory managment mechanism */
  354.     init_mac_alloc();
  355.  
  356.     /* Find the default (MacRTrace) directory */
  357.     error = HGetVol (volume_name, &rtrace_vrefnum, &rtrace_dirid);
  358.     if (error) terminal_error(error);
  359.  
  360.     /* Make it a working directory */
  361.     rtrace_wd_id = make_working_directory(rtrace_vrefnum, rtrace_dirid);
  362.     
  363.     /* Set up the log window */
  364.     setup_log_window();
  365.     
  366.     /* Get the preferences */
  367.     get_preferences();
  368.     
  369.     /* Move the scroll bars in the log window to agree with its new size */
  370.     log_window_resized();
  371.     
  372.     /* Show the log window */
  373.     show_log_window(FALSE);
  374.     
  375.     /* Grow the application zone to the maximum */
  376.     MaxApplZone();
  377.  
  378.     /* Set up our temporary items folder */
  379.     setup_temp_folder();
  380.  
  381. }    /* init_mac() */
  382.  
  383.  
  384.  
  385. /*****************************************************************************\
  386. * procedure get_system_info()                                                 *
  387. *                                                                             *
  388. * Purpose: This procedure determines what kind of system is installed, and    *
  389. *          various other system-specific tidbits.  It sets globals so that we *
  390. *          can determine later what the capabilities of the system are.       *
  391. *                                                                             *
  392. * Created by: Reid Judd                                                       *
  393. * Created on: September 9, 1992                                               *
  394. * Modified:                                                                   *
  395. *   WHO          WHEN             WHAT                                        *
  396. *   Greg Ferrar  9/10/92          Interfaced with my code, added other checks *
  397. \*****************************************************************************/
  398.  
  399. void get_system_info(void)
  400. {
  401.  
  402. #define Gestalttest             0xA1AD
  403. #define NoTrap                  0xA89F
  404.  
  405.     GDHandle    gdh; 
  406.  
  407.     short        error;
  408.     long        feature;
  409.     long        quickdraw_version;
  410.     SysEnvRec    sys_environ;
  411.     
  412.     gdh = GetGDevice();    
  413.     display_depth = (**(**gdh).gdPMap).pixelSize;
  414.  
  415.     /* Find the blessed folder */
  416.     error = SysEnvirons (1, &sys_environ);
  417.     if (error) terminal_error(error);
  418.     blessed_folder_wd_id = sys_environ.sysVRefNum;
  419.  
  420.     /* Check for availability of Gestalt, alert user if not present */
  421.     if (GetTrapAddress(Gestalttest) == GetTrapAddress(NoTrap))
  422.         {
  423.  
  424.         /* No Gestalt-- find the info from SysEnvirons */
  425.         fpu_available = sys_environ.hasFPU;
  426.         mc68020_available = ((sys_environ.processor != 1) && (sys_environ.processor != 2));
  427.         f8bit_QD_available = sys_environ.hasColorQD;
  428.         f32bit_QD_available = FALSE;            /* only on machines with Gestalt */
  429.         dither_copy_available = FALSE;            /* only on machines with Gestalt */
  430.         find_folder_available = FALSE;            /* only on machines with Gestalt */
  431.         notification_manager_available = FALSE;    /* only on machines with Gestalt */
  432.         apple_events_available = FALSE;            /* only on machines with Gestalt */
  433.         quicktime_available = FALSE;            /* only on machines with Gestalt */
  434.                 
  435.         }
  436.  
  437.     else    /* Use Gestalt */
  438.         {
  439.         
  440.         /* Find out whether QuickTime is available */
  441.         error = Gestalt(gestaltQuickTime, &feature);
  442.         if (error == gestaltUndefSelectorErr)
  443.             quicktime_available = FALSE;
  444.         else
  445.             {
  446.             if (error) terminal_error(error);
  447.             quicktime_available = (feature != 0);
  448.             }
  449.     
  450.         /* Find out whether Apple Events are available */
  451.         error = Gestalt(gestaltAppleEventsAttr, &feature);
  452.         if (error == gestaltUndefSelectorErr)
  453.             apple_events_available = FALSE;
  454.         else
  455.             {
  456.             if (error) terminal_error(error);
  457.             apple_events_available = feature & 1<<gestaltAppleEventsPresent;
  458.             }
  459.     
  460.         /* Find out whether FindFolder is available */
  461.         error = Gestalt(gestaltFindFolderAttr, &feature);
  462.         if (error == gestaltUndefSelectorErr)
  463.             find_folder_available = FALSE;
  464.         else
  465.             {
  466.             if (error) terminal_error(error);
  467.             find_folder_available = feature & 1<<gestaltFindFolderPresent;
  468.             }
  469.     
  470.         /* Find out whether the Notification Manager is available */
  471.         error = Gestalt(gestaltNotificationMgrAttr, &feature);
  472.         if (error == gestaltUndefSelectorErr)
  473.             notification_manager_available = FALSE;
  474.         else
  475.             {
  476.             if (error) terminal_error(error);
  477.             notification_manager_available = feature & 1<<gestaltNotificationPresent;
  478.             }
  479.     
  480.         /* Find the processor type */
  481.         error = Gestalt(gestaltProcessorType, &feature);
  482.         if (error) terminal_error(error);
  483.         mc68020_available = (feature >= gestalt68020);
  484.     
  485.         /* Find out whether there is a fpu */
  486.         error = Gestalt(gestaltFPUType, &feature);
  487.         if (error) terminal_error(error);
  488.         fpu_available = (feature != gestaltNoFPU);
  489.     
  490.         /* Find the version of QuickDraw */
  491.         error = Gestalt(gestaltQuickdrawVersion, &quickdraw_version);
  492.         if (error) terminal_error(error);
  493.         f8bit_QD_available = (quickdraw_version >= gestalt8BitQD);
  494.         f32bit_QD_available = (quickdraw_version >= gestalt32BitQD);
  495.         dither_copy_available = (quickdraw_version >= gestalt32BitQD13);
  496.         
  497.         }
  498.  
  499.     /* If this isn't at least a 68020, abort */
  500.     if (!mc68020_available)
  501.         terminal_string_error("MacRTrace requires at least a 68020 processor.");        
  502.  
  503.     /* If there isn't an fpu, abort */
  504.     if (!fpu_available)
  505.         terminal_string_error("MacRTrace requires a math coprocessor.");        
  506.     
  507.     /* If this is Original QuickDraw, warn the user */
  508.     if (!f8bit_QD_available)
  509.         {
  510.         possibly_terminal_string_error("MacRTrace prefers Color QuickDraw.  You may continue, \
  511. but you will not be able to see the image or to use the clipboard.");        
  512.         }
  513.  
  514.     /* If this is 8-bit QuickDraw, warn the user */
  515.     else if (!f32bit_QD_available)
  516.         {
  517.         possibly_terminal_string_error("MacRTrace prefers 32-bit Color QuickDraw.  You may continue, \
  518. but you will not be able to keep the image in memory or to use the clipboard.");        
  519.         }
  520.         
  521.         
  522.     DB(" This system has these capabilities......\n");    
  523.     if (fpu_available)
  524.       DB("fpu_available.")
  525.     else
  526.       DB("NO fpu_available.");
  527.     
  528.     if (mc68020_available)
  529.       DB("mc68020_available.")
  530.     else
  531.       DB("NO mc68020_available.");
  532.     
  533.      if (f8bit_QD_available)
  534.        DB("f8bit_QD_available.")
  535.      else
  536.        DB("NO f8bit_QD_available.");
  537.      
  538.      if (f32bit_QD_available)
  539.        DB("f32bit_QD_available.")
  540.      else
  541.        DB("NO f32bit_QD_available.");
  542.      
  543.      if (dither_copy_available)
  544.        DB("dither_copy_available ")
  545.      else
  546.        DB("NO dither_copy_available ");
  547.     
  548.      if (find_folder_available)
  549.        DB("find_folder_available.")
  550.      else
  551.        DB("find_folder_available.");
  552.      
  553.      if (notification_manager_available)
  554.        DB("notification_manager_available.")
  555.      else
  556.        DB("NO notification_manager_available.");
  557.      
  558.      if (apple_events_available)
  559.        DB("apple_events_available.")
  560.      else
  561.        DB("NO apple_events_available.");
  562.      
  563.      if (quicktime_available)
  564.        DB("quicktime_available.")
  565.      else
  566.        DB("NO quicktime_available.");
  567.          
  568. }    /* get_system_info() */
  569.  
  570.  
  571.  
  572. /*****************************************************************************\
  573. * procedure init_mgrs                                                         *
  574. *                                                                             *
  575. * Purpose: This procedure initializes the ToolBox managers so RTrace can look *
  576. *          and act like a standard Mac application.                           *
  577. *                                                                             *
  578. * Created by: Greg Ferrar                                                     *
  579. * Created on: August 21, 1992                                                 *
  580. * Modified:                                                                   *
  581. \*****************************************************************************/
  582.  
  583. void init_mgrs(void)
  584. {
  585.  
  586.     InitGraf(&thePort);
  587.     InitFonts();
  588.     FlushEvents(everyEvent, 0);
  589.     InitWindows();
  590.     InitDialogs(0);
  591.     InitCursor();
  592.     InitMenus();
  593.     TEInit();
  594.  
  595. }    /* init_mgrs() */
  596.  
  597.  
  598.  
  599. /*****************************************************************************\
  600. * procedure init_apple_events                                                 *
  601. *                                                                             *
  602. * Purpose: This procedure installs the handlers for the basic Apple Events.   *
  603. *                                                                             *
  604. * Created by: Greg Ferrar                                                     *
  605. * Created on: September 20, 1992                                              *
  606. * Modified:                                                                   *
  607. \*****************************************************************************/
  608.  
  609. void init_apple_events(void)
  610. {
  611.  
  612.     short error;
  613.     
  614.     /* Install the OpenApplication event handler */
  615.     error = AEInstallEventHandler(kCoreEventClass, kAEOpenApplication,
  616.                 open_app_ae_handler, 0, FALSE);
  617.     if (error) terminal_error(error);
  618.     
  619.     /* Install the OpenDocuments event handler */
  620.     error = AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments,
  621.                 open_docs_ae_handler, 0, FALSE);
  622.     if (error) terminal_error(error);
  623.     
  624.     /* Install the QuitApplication event handler */
  625.     error = AEInstallEventHandler(kCoreEventClass, kAEQuitApplication,
  626.                 quit_app_ae_handler, 0, FALSE);
  627.     if (error) terminal_error(error);
  628.     
  629. }    /* init_apple_events() */
  630.  
  631.  
  632.  
  633. /*****************************************************************************\
  634. * procedure init_menus                                                        *
  635. *                                                                             *
  636. * Purpose: This procedure initializes the mac pull-down menus.                *
  637. *                                                                             *
  638. * Created by: Greg Ferrar                                                     *
  639. * Created on: August 21, 1992                                                 *
  640. * Modified:                                                                   *
  641. \*****************************************************************************/
  642.  
  643. void init_menus()
  644. {
  645.  
  646.     /* Read the menus in to the menu list */
  647.     InsertMenu(apple_menu = GetMenu(APPLE_MENU), 0);
  648.     InsertMenu(file_menu = GetMenu(FILE_MENU), 0);
  649.     InsertMenu(edit_menu = GetMenu(EDIT_MENU), 0);
  650.     InsertMenu(windows_menu = GetMenu(WINDOWS_MENU), 0);
  651.     DrawMenuBar();    /* Draw the new menu bar */
  652.     
  653.     /* add the desk accessories */
  654.     AddResMenu(apple_menu, 'DRVR');
  655.  
  656.     /* Disable the editing commands in the Edit menu */
  657.     DisableItem(edit_menu, UNDO_ITEM);
  658.     DisableItem(edit_menu, CUT_ITEM);
  659.     DisableItem(edit_menu, COPY_ITEM);
  660.     DisableItem(edit_menu, PASTE_ITEM);
  661.     DisableItem(edit_menu, CLEAR_ITEM);
  662.  
  663.     /* Disable the Save... command in the File menu */
  664.     DisableItem(file_menu, SAVE_ITEM);
  665.  
  666. }    /* init_menus() */
  667.  
  668.  
  669.  
  670. /*****************************************************************************\
  671. * procedure mac_halt                                                          *
  672. *                                                                             *
  673. * Purpose: This procedure is called then rtrace tries to HALT (i.e. when an   *
  674. *          error occurs).  It puts up a dialog and attempts to continue.      *
  675. *                                                                             *
  676. * Created by: Greg Ferrar                                                     *
  677. * Created on: August 31, 1992                                                 *
  678. * Modified:                                                                   *
  679. *   WHO          WHEN             WHAT                                        *
  680. \*****************************************************************************/
  681.  
  682. void mac_halt(void)
  683. {
  684.  
  685.     char    error_message[100];
  686.  
  687.     /* look in stderr for an error message.  If fgets returns NULL, 
  688.         there is nothing there. */
  689.     fsetpos(stderr_file, ¤t_stderr_read_pos);
  690.     if (!fgets (error_message, 10000, stderr_file))
  691.         {
  692.  
  693.         /* Look at the end of the log text for an error message.  The
  694.             last line is an error message if it begins with "Error:" */
  695.         if (strstr(last_log_line, "Error:") == last_log_line)
  696.             strcpy (error_message, last_log_line);
  697.             
  698.         else    /* unidentified error */
  699.             strcpy (error_message, "Sorry, an unknown type of error occurred!");
  700.         
  701.         }
  702.     
  703.     else
  704.         
  705.         /* Chop of the newline from the stderr_file message */
  706.         error_message[strlen(error_message)-1] = 0;
  707.     
  708.     /* Put up an error alert, clean up, and go back to the event loop */
  709.     abortive_string_error(error_message);
  710.  
  711.     /* remember where we are in the stderr_file for later */
  712.     fgetpos(stderr_file, ¤t_stderr_read_pos);
  713.     
  714. }    /* mac_halt() */
  715.  
  716.  
  717.  
  718. /*****************************************************************************\
  719. * procedure process_mac_event                                                 *
  720. *                                                                             *
  721. * Purpose: This processes a single mac event.                                 *
  722. *                                                                             *
  723. * Created by: Greg Ferrar                                                     *
  724. * Created on: August 24, 1992                                                 *
  725. * Modified:                                                                   *
  726. \*****************************************************************************/
  727.  
  728. void process_mac_event(void)
  729.  
  730. {
  731.     EventRecord    event;
  732.     long         menu_result;
  733.     Boolean        valid;
  734.     DialogPtr    dialog;
  735.     short        item_hit;
  736.  
  737.  
  738.     /* if we aren't rendering, this is a loop.  If we are, it's just a
  739.         subroutine, and returns after one iteration */
  740.     do
  741.         {
  742.         
  743.         /* Don't call again for a bit */
  744.         get_another_event = FALSE;
  745.     
  746.         /* Get an event, allow background tasks time to work.  While rendering, we give
  747.             background tasks minimum time; while not rendering, they get as a little more. */
  748.         
  749.         if (rendering)
  750.             valid = WaitNextEvent(everyEvent, &event, 0, (RgnHandle) 0L);
  751.     
  752.         else
  753.             valid = WaitNextEvent(everyEvent, &event, 20, (RgnHandle) 0L);
  754.     
  755.         /* Check for event in the Options Dialog */
  756.         if (handle_dialog_event(&event))
  757.             continue;
  758.             
  759.         if (valid)
  760.             {
  761.         
  762.             switch (event.what)
  763.                 {
  764.                 case nullEvent:
  765.                     break;
  766.                 case mouseDown:
  767.                     do_mouse_down(&event);
  768.                 case mouseUp:
  769.                 case keyDown:                
  770.                     handle_key_down(&event);
  771.                     break;
  772.                 
  773.                 case keyUp:
  774.                 case autoKey:
  775.                     break;
  776.                 case updateEvt:
  777.                     handle_update_event((WindowPtr) event.message);
  778.                     break;
  779.                 case diskEvt:
  780.                     break;
  781.                 case activateEvt:
  782.                     if (((WindowPtr) event.message) == log_window)
  783.                         update_scroll_bar_with_active(event.modifiers & activeFlag);
  784.                         DrawGrowIcon(log_window);
  785.                     break;
  786.                     
  787.                 case networkEvt:
  788.                 case driverEvt:
  789.                 case app1Evt:
  790.                 case app2Evt:
  791.                 case app3Evt:
  792.                 case app4Evt:    
  793.                      handle_multifinder_event(&event);
  794.         
  795.                 case kHighLevelEvent:
  796.                       handle_high_level_event(&event);
  797.                     break;
  798.                     
  799.                 default:
  800.                     break;
  801.                 }
  802.             }
  803.         }
  804.         
  805.     while (!rendering);
  806.     
  807.     /* Set the GrafPort to the image window, in case the event changed it */ 
  808.     SetPort(image_window);
  809.  
  810. }    /* process_mac_event() */
  811.  
  812.  
  813.  
  814. /*****************************************************************************\
  815. * procedure open_app_ae_handler                                               *
  816. *                                                                             *
  817. * Purpose: This procedure handles an OpenApplication AppleEvent.              *
  818. *                                                                             *
  819. * Parameters: aevent: the OpenApplication AppleEvent.                         *
  820. *             reply:  the reply AppleEvent.                                   *
  821. *             handler_refcon: reference constant                              *
  822. *             returns an error code                                           *
  823. *                                                                             *
  824. * Created by: Greg Ferrar                                                     *
  825. * Created on: September 20, 1992                                              *
  826. * Modified:                                                                   *
  827. \*****************************************************************************/
  828.  
  829. pascal OSErr open_app_ae_handler(AppleEvent *aevent, AppleEvent *reply, long handler_refcon)
  830. {
  831.  
  832.     short    error;
  833.     
  834.      /* Get the required parameters */
  835.     error = got_required_parameters(aevent);
  836.  
  837.     /* If there was an error, return it */
  838.     if (error)
  839.         return error;
  840.  
  841.     /* No error */
  842.     return noErr;
  843.  
  844. }    /* open_app_ae_handler() */
  845.  
  846.  
  847.  
  848. /*****************************************************************************\
  849. * procedure quit_app_ae_handler                                               *
  850. *                                                                             *
  851. * Purpose: This procedure handles a QuitApplication AppleEvent.               *
  852. *                                                                             *
  853. * Parameters: aevent: the QuitApplication AppleEvent.                         *
  854. *             reply:  the reply AppleEvent.                                   *
  855. *             handler_refcon: reference constant                              *
  856. *             returns an error code                                           *
  857. *                                                                             *
  858. * Created by: Greg Ferrar                                                     *
  859. * Created on: September 20, 1992                                              *
  860. * Modified:                                                                   *
  861. \*****************************************************************************/
  862.  
  863. pascal OSErr quit_app_ae_handler(AppleEvent *aevent, AppleEvent *reply, long handler_refcon)
  864. {
  865.  
  866.     short    error;
  867.     Boolean    user_cancelled;
  868.  
  869.     /* check for missing required parameters */
  870.     error = got_required_parameters(aevent);
  871.     if (error)
  872.         return error;
  873.         
  874.     else
  875.         {
  876.         
  877.         /* If there is an unsaved image, check if the user really wants to quit */
  878.         user_cancelled = prepare_to_terminate();
  879.         
  880.         if (user_cancelled)
  881.             return userCanceledErr;        /* user didn't want to quit */
  882.         
  883.         else
  884.             return noErr;                /* user wanted to quit */
  885.  
  886.         }
  887.  
  888. }    /* quit_app_ae_handler() */
  889.  
  890.  
  891.  
  892. /*****************************************************************************\
  893. * procedure open_docs_ae_handler                                              *
  894. *                                                                             *
  895. * Purpose: This procedure handles a OpenDocuments AppleEvent.                 *
  896. *                                                                             *
  897. * Parameters: aevent: the OpenDocuments AppleEvent.                           *
  898. *             reply:  the reply AppleEvent.                                   *
  899. *             handler_refcon: reference constant                              *
  900. *             returns an error code                                           *
  901. *                                                                             *
  902. * Created by: Greg Ferrar                                                     *
  903. * Created on: September 20, 1992                                              *
  904. * Modified:                                                                   *
  905. *   Reid Judd   Oct 18,'92        Added 'if (error)' test before calling        *
  906. *                                 abortive_error().                           *
  907. \*****************************************************************************/
  908.  
  909. pascal OSErr open_docs_ae_handler(AppleEvent *aevent, AppleEvent *reply, long handler_refcon)
  910. {
  911.  
  912.     short        error;
  913.     AEDescList    document_list;
  914.     long        num_docs;
  915.     long        i;
  916.     Size        actual_size;
  917.     AEKeyword    keyword;
  918.     DescType    returned_type;
  919.     char        open_doc_error_message[] = "Error opening documents.";
  920.     FSSpec        fss;
  921.  
  922.      
  923.     /* Get the direct parameter--a descriptor list-- and put it into document_list */
  924.     error = AEGetParamDesc(aevent, keyDirectObject, typeAEList, &document_list);
  925.     if (error)
  926.         abortive_error(error);
  927.          
  928.     /* check for missing required parameters */
  929.     error = got_required_parameters(aevent);
  930.     if (error)
  931.         abortive_error(error);
  932.  
  933.     /* Count the number of document in the list */
  934.     error = AECountItems(&document_list, &num_docs);
  935.     if (error)
  936.         abortive_error(error);
  937.     
  938.      /* Get each descriptor record from the list, and open the first file
  939.         ending in ".sff".  We can only have one scene open at a time, and we
  940.         can only open .sff files. */
  941.     for (i = 1; i <= num_docs; i++)
  942.         {
  943.      
  944.         /* Get the info for this file */
  945.         error = AEGetNthPtr(&document_list, i, typeFSS, &keyword, &returned_type,
  946.                             (Ptr)&fss, sizeof(FSSpec), &actual_size);
  947.         if (error)
  948.             abortive_error(error);
  949.          
  950.         /* Does this file end in .sff?  If so, open it and we're done. */
  951.         PtoCstr(fss.name);
  952.         if (!strcmp((char *) (fss.name + strlen((char*)fss.name) - 4), ".sff"))
  953.             {             
  954.             CtoPstr(fss.name);
  955.             handle_open(&fss);
  956.             break;
  957.             }
  958.         }
  959.  
  960. }    /* open_docs_ae_handler() */
  961.  
  962.  
  963.  
  964. /*****************************************************************************\
  965. * procedure got_required_parameters                                           *
  966. *                                                                             *
  967. * Purpose: This procedure checks for any further required parameters in an    *
  968. *          Apple Event.                                                       *
  969. *                                                                             *
  970. * Parameters: aevent: the Apple Event.                                        *
  971. *                                                                             *
  972. * Created by: Greg Ferrar                                                     *
  973. * Created on: September 20, 1992                                              *
  974. * Modified:                                                                   *
  975. \*****************************************************************************/
  976.  
  977. OSErr got_required_parameters(AppleEvent *aevent)
  978. {
  979.  
  980.     DescType    returned_type;
  981.     Size        actual_size;
  982.     OSErr        error;
  983.  
  984.     /* Check for any further required parameters */
  985.     error = AEGetAttributePtr(aevent, keyMissedKeywordAttr, typeWildCard,
  986.                                 &returned_type, NULL, 0, &actual_size);
  987.  
  988.     /* If another parameter was not found, there are no more, so we're done. */
  989.     if (error = errAEDescNotFound)
  990.         return (noErr);
  991.  
  992.     else if (error = noErr)
  993.         return errAEEventNotHandled;    /* there's still a parameter */
  994.  
  995.     else
  996.         return noErr;
  997.         
  998. }    /* got_required_parameters() */
  999.  
  1000.  
  1001.  
  1002. /*****************************************************************************\
  1003. * procedure prepare_to_terminate                                              *
  1004. *                                                                             *
  1005. * Purpose: This procedure prompt the user whether or not to save the image or *
  1006. *          animation before quitting.                                         *
  1007. *                                                                             *
  1008. * Parameters: returns TRUE if user cancelled (doesn't want to quit)           *
  1009. *                                                                             *
  1010. * Created by: Greg Ferrar                                                     *
  1011. * Created on: September 20, 1992                                              *
  1012. * Modified:                                                                   *
  1013. \*****************************************************************************/
  1014.  
  1015. Boolean prepare_to_terminate(void)
  1016. {
  1017.  
  1018.     short item_hit;
  1019.  
  1020.     /* If the image/animation is saved, don't do anything */
  1021.     if (!image_saved)
  1022.         {
  1023.         
  1024.         /* Choose the correct word, depending on whether it's an animation or
  1025.             a still image */
  1026.         ParamText(GetCtlValue(animate_checkbox) ? "\panimation sequence" : "\pimage", 0, 0, 0);
  1027.  
  1028.         /* Prompt the user whether (s)he wants to save the image/animation and quit,
  1029.             discard it and quit, or cancel the quit process */
  1030.         ShowWindow(prompt_save_dialog);
  1031.         SelectWindow(prompt_save_dialog);
  1032.         ModalDialog ((ProcPtr) NULL, &item_hit);
  1033.         HideWindow(prompt_save_dialog);
  1034.         
  1035.         if (item_hit == PROMPT_SAVE_CANCEL_BUTTON)
  1036.             return TRUE;
  1037.         
  1038.         else if (item_hit == PROMPT_SAVE_SAVE_BUTTON)
  1039.             handle_save();
  1040.  
  1041.         }
  1042.  
  1043.     /* User does want to quit */
  1044.     return FALSE;
  1045.  
  1046. }    /* prepare_to_terminate() */
  1047.  
  1048.  
  1049. /*****************************************************************************\
  1050. * procedure handle_key_down                                                   *
  1051. *                                                                             *
  1052. * Purpose: This procedure handles a key down event.                           *
  1053. *                                                                             *
  1054. * Parameters: event: the event.                                               *
  1055. *                                                                             *
  1056. * Created by: Greg Ferrar                                                     *
  1057. * Created on: September 14, 1992                                              *
  1058. * Modified:                                                                   *
  1059. \*****************************************************************************/
  1060.  
  1061. void handle_key_down(EventRecord *event)
  1062. {
  1063.  
  1064.     short     item_hit;
  1065.     long    menu_result;
  1066.  
  1067.     /* Check for menu shortcut */
  1068.     if (event->modifiers & cmdKey)
  1069.         {
  1070.          
  1071.         /* Command-period during render cancels */
  1072.         if ((event->message & charCodeMask) == '.')
  1073.  
  1074.             {
  1075.  
  1076.             /* If we're not rendering, don't do anything */
  1077.             if (!rendering)
  1078.                 return;
  1079.  
  1080.             /* verify that user really wants to cancel */
  1081.             ShowWindow(cancel_dialog);
  1082.             SelectWindow(cancel_dialog);
  1083.             ModalDialog ((ProcPtr) NULL, &item_hit);
  1084.             HideWindow(cancel_dialog);
  1085.  
  1086.             if (item_hit != DONT_ABORT_BUTTON)
  1087.                 {
  1088.                 post_render(FALSE);
  1089.                 
  1090.                 /* Render cancelled-- restore startup environment
  1091.                     and start again */
  1092.                 longjmp(environment, 1);
  1093.                 
  1094.                 }
  1095.             
  1096.             return;
  1097.             
  1098.             }
  1099.         
  1100.         /* Find menu equivalent */
  1101.         menu_result = MenuKey(event->message);
  1102.         
  1103.         /* Pretend user clicked menu */
  1104.         if (HiWord(menu_result) != 0)    /* valid key? */
  1105.             do_menu (menu_result);        /* yes, map it to menu item */
  1106.         }
  1107.  
  1108. }    /* handle_key_down() */
  1109.  
  1110.  
  1111.  
  1112. /*****************************************************************************\
  1113. * procedure handle_high_level_event                                           *
  1114. *                                                                             *
  1115. * Purpose: This procedure handles a high level event.                         *
  1116. *                                                                             *
  1117. * Parameters: event: the event.                                               *
  1118. *                                                                             *
  1119. * Created by: Greg Ferrar                                                     *
  1120. * Created on: September 20, 1992                                              *
  1121. * Modified:                                                                   *
  1122. \*****************************************************************************/
  1123.  
  1124. void handle_high_level_event(EventRecord *event)
  1125. {
  1126.      /* Process this AppleEvent */
  1127.     AEProcessAppleEvent(event);
  1128.     
  1129. }    /* handle_high_level_event() */
  1130.  
  1131.  
  1132.  
  1133. /*****************************************************************************\
  1134. * procedure handle_multifinder_event                                          *
  1135. *                                                                             *
  1136. * Purpose: This procedure handles a multifinder event.                        *
  1137. *                                                                             *
  1138. * Parameters: event: the event.                                               *
  1139. *                                                                             *
  1140. * Created by: Greg Ferrar                                                     *
  1141. * Created on: September 14, 1992                                              *
  1142. * Modified:                                                                   *
  1143. \*****************************************************************************/
  1144.  
  1145. void handle_multifinder_event(EventRecord *event)
  1146. {
  1147.  
  1148.     /* Check for multifinder event */
  1149.     if (event->message & 0x01000000)
  1150.         {
  1151.  
  1152.         /* Check for coming to foreground event */
  1153.         if (event->message & 0x00000001)
  1154.             {
  1155.             
  1156.             /* Coming to foreground... */
  1157.             in_background = FALSE;
  1158.             
  1159.             /* If there's a notification installed, remove it */
  1160.             if (notification_installed)
  1161.                 {
  1162.                 NMRemove(¬ification);
  1163.                 notification_installed = FALSE;
  1164.                 }
  1165.  
  1166.             /* Activate log window if it's front */
  1167.             if (FrontWindow() == log_window)
  1168.                 {
  1169.                 
  1170.                 update_scroll_bar_with_active(TRUE);
  1171.                 DrawGrowIcon(log_window);
  1172.                 
  1173.                 }
  1174.             }
  1175.             
  1176.         else
  1177.             {
  1178.             
  1179.             /* Going to background... */
  1180.             in_background = TRUE;
  1181.             
  1182.             /* Deactivate the log window */
  1183.             if (FrontWindow() == log_window)
  1184.                 {
  1185.                 
  1186.                 update_scroll_bar_with_active(FALSE);
  1187.                 DrawGrowIcon(log_window);
  1188.                 
  1189.                 }
  1190.             }
  1191.         }
  1192.         
  1193. }    /* handle_multifinder_event() */
  1194.  
  1195.  
  1196.  
  1197. /*****************************************************************************\
  1198. * procedure handle_dialog_event                                               *
  1199. *                                                                             *
  1200. * Purpose: This procedure handles a dialog event.                             *
  1201. *                                                                             *
  1202. * Parameters: event: the event.                                               *
  1203. *                                                                             *
  1204. * Created by: Greg Ferrar                                                     *
  1205. * Created on: September 14, 1992                                              *
  1206. * Modified:                                                                   *
  1207. \*****************************************************************************/
  1208.  
  1209. Boolean handle_dialog_event(EventRecord *event)
  1210. {
  1211.     
  1212.     DialogPtr    dialog;
  1213.     short        item_hit;
  1214.     static long    num_calls = 0;
  1215.     
  1216.     /* Find if there's really a dialog event */
  1217.     if (IsDialogEvent(event))
  1218.         {
  1219.     
  1220.         /* If it's a return, treat it like a click of the default button */
  1221.         if ( (event->what == keyDown) && 
  1222.              ( ((event->message & charCodeMask) == '\r') ||
  1223.                ((event->message & charCodeMask) == '\3') ) )            
  1224.           {
  1225.             /* If it's in the options dialog, fake a Render click */
  1226.             if (FrontWindow() == options_dialog)
  1227.                 {
  1228.                 
  1229.                 /* Fake a click in the Render button */
  1230.                 HiliteControl(render_button_handle, inButton);
  1231.                 
  1232.                 /* handle a click in the Render button */
  1233.                 handle_options_selection(RENDER_BUTTON);
  1234.                 
  1235.                 }
  1236.             
  1237.             /* if it's in the Animation dialog, fake an Okay click */
  1238.             else if (FrontWindow() == animation_dialog)
  1239.                 {
  1240.                 
  1241.                 /* Fake a click in the Okay button */
  1242.                 HiliteControl(animation_okay_button_handle, inButton);
  1243.                 
  1244.                 /* handle a click in the Okay button */
  1245.                 handle_animation_selection(OKAY_BUTTON);
  1246.                 
  1247.                 }
  1248.             
  1249.             /* if it's in the Animation dialog, fake an Okay click */
  1250.             else if (FrontWindow() == preferences_dialog)
  1251.                 {
  1252.                 
  1253.                 /* Fake a click in the Okay button */
  1254.                 HiliteControl(preferences_okay_button_handle, inButton);
  1255.                 
  1256.                 /* handle a click in the Okay button */
  1257.                 handle_preferences_selection(OKAY_BUTTON);
  1258.                 
  1259.                 }
  1260.             
  1261.             /* Don't handle this as a normal event */
  1262.             return TRUE;
  1263.             
  1264.             }
  1265.  
  1266.  
  1267.         num_calls++;
  1268.         
  1269.         if (DialogSelect (event, &dialog, &item_hit))
  1270.             
  1271.             {
  1272.             
  1273.             /* Something was selected-- handle it */
  1274.             if (dialog == options_dialog)
  1275.                 handle_options_selection (item_hit);
  1276.     
  1277.             else if (dialog == animation_dialog)
  1278.                 handle_animation_selection (item_hit);
  1279.             
  1280.             else if (dialog == preferences_dialog)
  1281.                 handle_preferences_selection (item_hit);
  1282.             
  1283.             }
  1284.         }
  1285.     
  1286.         
  1287.     /* Handle this as a normal event */
  1288.     return FALSE;
  1289.  
  1290. }    /* handle_dialog_event() */
  1291.  
  1292.  
  1293.  
  1294. /*****************************************************************************\
  1295. * procedure handle_update_event                                               *
  1296. *                                                                             *
  1297. * Purpose: This procedure handles a window update event.                      *
  1298. *                                                                             *
  1299. * Parameters: the_window: the window being updated.                           *
  1300. *                                                                             *
  1301. * Created by: Greg Ferrar                                                     *
  1302. * Created on: August 24, 1992                                                 *
  1303. * Modified:                                                                   *
  1304. \*****************************************************************************/
  1305.  
  1306. void handle_update_event(WindowPtr the_window)
  1307. {
  1308.  
  1309.     short copy_mode;
  1310.  
  1311.     /* Check for update of the image window */
  1312.     if (the_window == image_window)
  1313.         {
  1314.         /* start the update event */
  1315.         BeginUpdate(the_window);
  1316.         
  1317.         /* Dither the image if dithering is available */
  1318.         copy_mode = (dither_copy_available) ? ditherCopy : srcCopy;
  1319.         
  1320.         /* If there's an offscreen pixmap, use it */
  1321.         if (is_offscreen_port)
  1322.             {
  1323.                 
  1324.             /* copy the offscreen pixmap to the window */
  1325.             CopyBits (&((GrafPtr) image_port)->portBits,
  1326.                         &((GrafPtr) the_window)->portBits,
  1327.                         &(image_port->portRect), &(image_port->portRect),
  1328.                         copy_mode, the_window->visRgn);
  1329.             }
  1330.         
  1331.         /* end the update event */
  1332.         EndUpdate (the_window);
  1333.         }
  1334.  
  1335.     /* Check for update of the log window */
  1336.     else if (the_window == log_window)
  1337.         update_log_window();
  1338.         
  1339.  
  1340. }    /* handle_update_event() */
  1341.  
  1342.  
  1343. /*****************************************************************************\
  1344. * procedure do_mouse_down                                                     *
  1345. *                                                                             *
  1346. * Purpose: This procedure handles a mouse down event.                         *
  1347. *                                                                             *
  1348. * Parameters: event: the event                                                *
  1349. *                                                                             *
  1350. * Created by: Greg Ferrar                                                     *
  1351. * Created on: August 22, 1992                                                 *
  1352. * Modified:                                                                   *
  1353. *   Reid Judd    Oct.16'92      Check for "if (mouse_window == log_window)" if  *
  1354. *                                 we are doing an inGrow mouse event.           *
  1355. *                                                                             *
  1356. \*****************************************************************************/
  1357.  
  1358. void do_mouse_down(EventRecord *event)
  1359. {
  1360.     WindowPtr    mouse_window;
  1361.     int         screen_area = FindWindow (event->where, &mouse_window);
  1362.     WStateData    **wstate_handle;
  1363.     GrafPtr        temp_port;
  1364.     
  1365.     switch (screen_area)
  1366.     {
  1367.         case inDesk:
  1368.             break;
  1369.             
  1370.         case inMenuBar:
  1371.             do_menu(MenuSelect(event->where));
  1372.             break;
  1373.             
  1374.         case inSysWindow:
  1375.             SystemClick(event, mouse_window);
  1376.             break;
  1377.             
  1378.         case inContent:
  1379.             if (mouse_window != FrontWindow())
  1380.                 {
  1381.                 SelectWindow (mouse_window);
  1382.                 SetPort(mouse_window);
  1383.                 }
  1384.             else if (mouse_window == log_window)
  1385.                 handle_log_click(event->where);
  1386.             break;
  1387.             
  1388.         case inDrag:
  1389.         
  1390.             /* Let the user draw the window around */
  1391.             DragWindow (mouse_window, event->where, &drag_window_rect);
  1392.             
  1393.             /* If it's the options dialog, redraw it so all the popups
  1394.                 find their new upper left point */
  1395.             if (mouse_window == options_dialog)
  1396.                 DrawDialog(options_dialog);
  1397.             
  1398.             /* Find the new window position, and save it (update WStateData) */
  1399.             wstate_handle = (WStateData **) ( (WindowPeek) mouse_window )->dataHandle;
  1400.  
  1401.             /* Save the window position, in local coordinates */
  1402.             BlockMove(&(mouse_window->portRect), &(*wstate_handle)->userState, 8);
  1403.  
  1404.             /* Convert the position to global coordinates */
  1405.             GetPort(&temp_port);
  1406.             SetPort(mouse_window);
  1407.             LocalToGlobal( (Point *) &(*wstate_handle)->userState);
  1408.             LocalToGlobal( (Point *) &((*wstate_handle)->userState.bottom));
  1409.             SetPort(temp_port);
  1410.             
  1411.             break;
  1412.             
  1413.         case inGrow:
  1414.             if (mouse_window == log_window)
  1415.                grow_log_window(event->where);
  1416.             break;
  1417.             
  1418.         case inGoAway:
  1419.         
  1420.             /* Track the goaway box until user releases mouse button */
  1421.             if (TrackGoAway (mouse_window, event->where))
  1422.                 {
  1423.                 
  1424.                 /* User released button inside goaway box-- which window
  1425.                     should we hide? */
  1426.                 if (mouse_window == options_dialog)
  1427.                     hide_options_dialog();
  1428.                 else if (mouse_window == status_dialog)
  1429.                     hide_status_dialog();
  1430.                 else if (mouse_window == animation_dialog)
  1431.                     hide_animation_dialog();
  1432.                 else if (mouse_window == image_window)
  1433.                     hide_image_window();
  1434.                 else if (mouse_window == log_window)
  1435.                     hide_log_window();
  1436.                 
  1437.                 }
  1438.                 
  1439.             break;
  1440.             
  1441.         case inZoomIn:
  1442.         case inZoomOut:
  1443.             
  1444.             /* Only the log window has a zoom box */
  1445.             handle_log_window_zoom(event->where, screen_area);
  1446.  
  1447.         default:
  1448.             break;
  1449.     }
  1450.     
  1451. }    /* do_mouse_down() */
  1452.  
  1453.  
  1454.  
  1455. /*****************************************************************************\
  1456. * procedure do_menu                                                           *
  1457. *                                                                             *
  1458. * Purpose: This procedure handles a pulldown menu selection.                  *
  1459. *                                                                             *
  1460. * Parameters: command: the menu selection; menu id in low word, menu item in  *
  1461. *                      high word                                              *
  1462. *                                                                             *
  1463. * Created by: Greg Ferrar                                                     *
  1464. * Created on: August 22, 1992                                                 *
  1465. * Modified:                                                                   *
  1466. \*****************************************************************************/
  1467.  
  1468. void do_menu(long command)
  1469. {
  1470.     int        menu_id = HiWord(command);
  1471.     int        item = LoWord(command);
  1472.     char    item_name[32];
  1473.     char    pathname[200];
  1474.     
  1475.     switch(menu_id)
  1476.     {
  1477.         case APPLE_MENU:
  1478.             if (item == ABOUT_ITEM) 
  1479.                 show_about_dialog();
  1480.             else
  1481.             {
  1482.                 GetItem(GetMHandle(menu_id), item, item_name);
  1483.                 OpenDeskAcc(item_name);
  1484.             }
  1485.                 break;
  1486.                 
  1487.         case FILE_MENU:
  1488.             
  1489.             switch (item)
  1490.             {
  1491.                 case OPEN_ITEM:
  1492.                     handle_open((FSSpec *) NULL);
  1493.                     break;
  1494.  
  1495.                 case SAVE_ITEM:
  1496.                     handle_save();
  1497.                     break;    
  1498.                 case QUIT_ITEM:
  1499.                     
  1500.                     /* Make sure user has a change to save file, or to abort the
  1501.                         quit */
  1502.                     if (!prepare_to_terminate())
  1503.                         {
  1504.                         
  1505.                         /* Get rid of any temp files left over from last render,
  1506.                             and get rid of the movie file */
  1507.                         delete_temp_files(TRUE);
  1508.                 
  1509.                         /* Write the preferences to disk */
  1510.                         write_preferences();
  1511.                         
  1512.                         /* Quit */
  1513.                         ExitToShell();
  1514.  
  1515.                         }
  1516.             }
  1517.             
  1518.             break;
  1519.  
  1520.         case EDIT_MENU:
  1521.         
  1522.             do_edit(item);
  1523.  
  1524.             break;
  1525.  
  1526.         case WINDOWS_MENU:    /* Show/Hide Windows */
  1527.         
  1528.             switch (item)
  1529.             {
  1530.             case SHOW_OPTIONS_ITEM:
  1531.                 
  1532.                 /* Toggle the visibility of the options dialog */
  1533.                 if (((WindowPeek)options_dialog)->visible)
  1534.                     hide_options_dialog();
  1535.                     
  1536.                 else
  1537.                     show_options_dialog(TRUE);
  1538.             
  1539.                 break;
  1540.  
  1541.             case SHOW_LOG_ITEM:
  1542.                 
  1543.                 /* Toggle the visibility of the log window */
  1544.                 if (((WindowPeek)log_window)->visible)
  1545.                     hide_log_window();
  1546.                     
  1547.                 else
  1548.                     show_log_window(TRUE);
  1549.             
  1550.                 break;
  1551.  
  1552.             case SHOW_STATUS_ITEM:
  1553.                 
  1554.                 /* Toggle the visibility of the status dialog */
  1555.                 if (((WindowPeek)status_dialog)->visible)
  1556.                     hide_status_dialog();
  1557.                     
  1558.                 else
  1559.                     show_status_dialog(TRUE);
  1560.             
  1561.                 break;
  1562.  
  1563.             case SHOW_ANIMATION_ITEM:
  1564.                 
  1565.                 /* Toggle the visibility of the animation dialog */
  1566.                 if (((WindowPeek)animation_dialog)->visible)
  1567.                     hide_animation_dialog();
  1568.                     
  1569.                 else
  1570.                     show_animation_dialog(TRUE);
  1571.             
  1572.                 break;
  1573.  
  1574.             case SHOW_IMAGE_ITEM:
  1575.                 
  1576.                 /* Toggle the visibility of the image window */
  1577.                 if (((WindowPeek)image_window)->visible)
  1578.                     hide_image_window();
  1579.                     
  1580.                 else
  1581.                     show_image_window(TRUE);
  1582.             
  1583.                 break;
  1584.                 
  1585.             }
  1586.  
  1587.     }
  1588.     
  1589.     HiliteMenu(0);
  1590. }
  1591.  
  1592.  
  1593.  
  1594. /*****************************************************************************\
  1595. * procedure do_edit                                                           *
  1596. *                                                                             *
  1597. * Purpose: This procedure handles an Edit menu selection.                     *
  1598. *                                                                             * 
  1599. * Parameters: item: the item selected.                                        *
  1600. *                                                                             *
  1601. * Created by: Greg Ferrar                                                     *
  1602. * Created on: August 22, 1992                                                 *
  1603. * Modified:                                                                   *
  1604. *   WHO          WHEN             WHAT                                        *
  1605. \*****************************************************************************/
  1606.  
  1607. void do_edit(short item)
  1608. {
  1609.     
  1610.     PicHandle        bitmap_picture;    /* a picture to be copied to the clipboard */
  1611.     OpenCPicParams    pic_params;        /* parameters for opening a picture */
  1612.  
  1613.  
  1614.     if (item == PREFERENCES_ITEM)
  1615.         show_preferences_dialog();    /* bring up the preferences dialog */
  1616.     
  1617.     if ((item == COPY_ITEM) && (keep_image_in_memory))
  1618.         {
  1619.         
  1620.         /* It's in memory-- make a PICT of it */
  1621.         BlockMove (&image_port->portRect, &pic_params.srcRect, 8);    /* copy the rect */
  1622.         pic_params.hRes = pic_params.vRes = (Fixed) 72 << 16;
  1623.         pic_params.version = -2;
  1624.         bitmap_picture = OpenCPicture (&pic_params);        
  1625.  
  1626.         /* copy the offscreen pixmap to the window */
  1627.         CopyBits (&((GrafPtr) image_port)->portBits,
  1628.                     &((GrafPtr) image_window)->portBits,
  1629.                     &(image_port->portRect), &(image_port->portRect),
  1630.                     srcCopy, ((GrafPtr) image_window)->visRgn);
  1631.     
  1632.         /* The picture is done-- close it */
  1633.         ClosePicture();
  1634.  
  1635.         /* Move the picture to the desk scrap */
  1636.         ZeroScrap();
  1637.         HLock (bitmap_picture);
  1638.         PutScrap(GetHandleSize(bitmap_picture), 'PICT', *bitmap_picture);
  1639.         HUnlock (bitmap_picture);
  1640.         
  1641.         /* Free the picture */
  1642.         KillPicture(bitmap_picture);
  1643.  
  1644.         }
  1645. }
  1646.  
  1647.  
  1648.  
  1649. /*****************************************************************************\
  1650. * procedure handle_open                                                       *
  1651. *                                                                             *
  1652. * Purpose: This procedure is called when the user selects Open... from the    *
  1653. *          file menu.  It allows the user to select a file, and gets the      *
  1654. *          pathname of the file to give to RTrace.  It then calls RTrace to   *
  1655. *          create the image.                                                  *
  1656. *                                                                             *                                                                             *
  1657. * Parameters: file_spec: the file to open, NULL if we should prompt user.     *
  1658. *                                                                             *                                                                             *
  1659. * Created by: Greg Ferrar                                                     *
  1660. * Created on: August 22, 1992                                                 *
  1661. * Modified:                                                                   *
  1662. *   WHO          WHEN             WHAT                                        *
  1663. *   Greg Ferrar  8/24/92          moved ray tracing code to ray_trace_sff     *
  1664. \*****************************************************************************/
  1665.  
  1666. void    handle_open(FSSpec *file_spec)
  1667. {
  1668.  
  1669.     char     window_name[200];
  1670.     short    error;
  1671.     FInfo    finder_info;
  1672.  
  1673.      if (file_spec)
  1674.         {
  1675.         
  1676.         /* Create a new working directory for the .sff directory */
  1677.         error = OpenWD (file_spec->vRefNum, file_spec->parID, 'RTRC', &sff_file_wd_id);
  1678.         if (error) abortive_error(error);
  1679.         
  1680.         /* Set the default directory to the .sff directory */
  1681.         SetVol ((StringPtr) NULL, sff_file_wd_id);
  1682.  
  1683.         /* Save the filename of this .sff file */
  1684.         strcpy (sff_filename, PtoCstr(file_spec->name));
  1685.  
  1686.         }
  1687.     
  1688.     else    /* Prompt the user for a file */
  1689.         {
  1690.         /* Get the filename of the .sff file */
  1691.         if (!open_sff_file(sff_filename))
  1692.             return;
  1693.         }
  1694.  
  1695.     /* Change the creator to RTRC */
  1696.     CtoPstr(sff_filename);
  1697.     error = GetFInfo (sff_filename, sff_file_wd_id, &finder_info);
  1698.     if (error) abortive_error(error);
  1699.     finder_info.fdCreator = 'RTRC';
  1700.     error = SetFInfo (sff_filename, sff_file_wd_id, &finder_info);
  1701.     if (error) abortive_error(error);
  1702.     PtoCstr(sff_filename);
  1703.  
  1704.     /* count the number of objects, lights, and surfaces in the sff file, and
  1705.         read in the eye, look, up and angles from the scene */
  1706.     preprocess_sff_file(&num_lights, &num_surfaces, &number_noncluster_objects);
  1707.  
  1708.     /* Set the animation dialog fields according to the data read from the
  1709.         sff file */
  1710.     set_dialog_real(animation_dialog, X_EYE_EQ, eye.x);
  1711.     set_dialog_real(animation_dialog, Y_EYE_EQ, eye.y);
  1712.     set_dialog_real(animation_dialog, Z_EYE_EQ, eye.z);
  1713.     set_dialog_real(animation_dialog, X_LOOK_EQ, look.x);
  1714.     set_dialog_real(animation_dialog, Y_LOOK_EQ, look.y);
  1715.     set_dialog_real(animation_dialog, Z_LOOK_EQ, look.z);
  1716.     set_dialog_real(animation_dialog, X_UP_EQ, up.x);
  1717.     set_dialog_real(animation_dialog, Y_UP_EQ, up.y);
  1718.     set_dialog_real(animation_dialog, Z_UP_EQ, up.z);
  1719.     set_dialog_real(animation_dialog, ANGLE_X_EQ, 180*view_angle_x/PI);
  1720.     set_dialog_real(animation_dialog, ANGLE_Y_EQ, 180*view_angle_y/PI);
  1721.  
  1722.     /* Change the name of the options dialog to reflect the filename */
  1723.     strcpy(window_name, "Options for ");
  1724.     strcat(window_name, sff_filename);
  1725.     window_name[strlen(window_name) - 4] = 0;    /* chop off .sff */
  1726.  
  1727.     /* Rename the window */
  1728.     SetWTitle (options_dialog, CtoPstr(window_name));    
  1729.     
  1730.     /* Remember that this new scene is not memory */
  1731.     scene_in_memory = FALSE;
  1732.     
  1733.     /* Remember that we are dealing with a new file now */
  1734.     rendering_same_file = FALSE;
  1735.     
  1736.     /* Update the render button to say "Render" */
  1737.     update_render_button();
  1738.     
  1739.     /* Show the Options dialog if it's not visible */
  1740.     show_options_dialog(TRUE);
  1741.  
  1742.     /* Allow user to show or hide Options dialog from now on */
  1743.     EnableItem (windows_menu, SHOW_OPTIONS_ITEM);
  1744.  
  1745.  
  1746. }
  1747.  
  1748.  
  1749. /*****************************************************************************\
  1750. * procedure handle_save                                                       *
  1751. *                                                                             *
  1752. * Purpose: This procedure is called when the user selects Save... from the    *
  1753. *          file menu.  It allows the user to select an output file and an     *
  1754. *          output file type.  It then saves the image to disk.                *
  1755. *                                                                             *                                                                             *
  1756. * Created by: Greg Ferrar                                                     *
  1757. * Created on: August 22, 1992                                                 *
  1758. * Modified:                                                                   *
  1759. *   WHO          WHEN             WHAT                                        *
  1760. \*****************************************************************************/
  1761.  
  1762. void    handle_save(void)
  1763. {
  1764.     
  1765.     Point    dialog_upper_left = {130, 80};
  1766.     SFReply    my_reply;            /* save file info */
  1767.     char    *filename;            /* the filename of the file to save to */
  1768.     
  1769.     /* get the filename of the file to save to */
  1770.     filename = get_save_filename();
  1771.     
  1772.     /* If this is animated, put up the animation save... dialog.  Otherwise,
  1773.         put up the image save... dialog. */
  1774.     if (GetCtlValue(animate_checkbox))
  1775.         {
  1776.         
  1777.         /* Put up the animation save... dialog */
  1778.         SFPPutFile(dialog_upper_left, "\pSave animation as:",
  1779.                     CtoPstr(filename), (ProcPtr) 0, &my_reply, SAVE_ANIM_DIALOG,
  1780.                     save_image_filter);
  1781.         
  1782.         /* Don't do anything if user cancelled */
  1783.         if (!my_reply.good)
  1784.             return;
  1785.         
  1786.         /* save the file according to its type */
  1787.         switch (save_anim_file_type_menu_selection)
  1788.             {
  1789.             case 1:    save_pict_files(&my_reply);
  1790.                     break;
  1791.             case 2: save_quicktime_movie(&my_reply);
  1792.             }
  1793.         }
  1794.     else
  1795.         {
  1796.         
  1797.         /* Put up the image save... dialog */
  1798.         SFPPutFile(dialog_upper_left, "\pSave image as:",
  1799.                     CtoPstr(filename), (ProcPtr) 0, &my_reply, SAVE_DIALOG,
  1800.                     save_image_filter);
  1801.  
  1802.         /* Don't do anything if user cancelled */
  1803.         if (!my_reply.good)
  1804.             return;
  1805.  
  1806.         /* save the file according to its type */
  1807.         switch (save_file_type_menu_selection)
  1808.             {
  1809.             case 1:    save_pict_file(&my_reply);
  1810.                     break;
  1811.             case 2: save_ppm_file(&my_reply);
  1812.             }
  1813.  
  1814.         }
  1815.  
  1816.     /* Remember that the image has been saved */
  1817.     image_saved = TRUE;
  1818.  
  1819. }    /* handle_save() */
  1820.  
  1821.  
  1822.  
  1823. /*****************************************************************************\
  1824. * procedure install_get_event_vbl                                             *
  1825. *                                                                             *
  1826. * Purpose: This procedure installs the VBL task which makes get_another_event *
  1827. *          TRUE every few ticks.                                              *
  1828. *                                                                             *
  1829. * Parameters: how_often: how often to give up control (if -1, REMOVE the task)*
  1830. *                                                                             *
  1831. * Created by: Greg Ferrar                                                     *
  1832. * Created on: August 31, 1992                                                 *
  1833. * Modified:                                                                   *
  1834. \*****************************************************************************/
  1835.  
  1836. /* We use this structure so that the VBL task can find our A5 and use it to
  1837.     access our globals */
  1838. typedef struct
  1839.     {
  1840.     long application_A5;
  1841.     VBLTask the_vbl_task;
  1842.     } VBL_task_A5_struct;
  1843.  
  1844. VBL_task_A5_struct        event_call_task;    /* installed task, if any */
  1845.  
  1846. void install_get_event_vbl(void)
  1847. {
  1848.  
  1849.     /* Install the screen refresh interrupt */
  1850.     event_call_task.the_vbl_task.qType = vType;
  1851.     event_call_task.the_vbl_task.vblAddr = (ProcPtr) set_event_flag;
  1852.     event_call_task.the_vbl_task.vblCount = time_between_events;
  1853.     event_call_task.the_vbl_task.vblPhase = 0; 
  1854.     
  1855.     /* Save the applications’s A5 where the VBL tasks can find it; right 
  1856.          before the VBL Task structure.  We need the VBL Tasks to have access
  1857.          to the application globals, so they need to know what the application’s
  1858.          A5 global pointer is. */
  1859.     event_call_task.application_A5 = (long) CurrentA5;    /* a Macintosh global */
  1860.  
  1861.     /* Install the task */        
  1862.     VInstall((QElemPtr)&event_call_task.the_vbl_task);
  1863.  
  1864.     /* Remember that the vbl task is installed */
  1865.     vbl_installed = TRUE;
  1866.  
  1867. }    /* install_get_event_vbl() */
  1868.  
  1869.  
  1870.  
  1871. /*****************************************************************************\
  1872. * procedure remove_get_event_vbl                                              *
  1873. *                                                                             *
  1874. * Purpose: This procedure removes the VBL task which makes get_another_event  *
  1875. *          TRUE every few ticks.                                              *
  1876. *                                                                             *
  1877. * Created by: Greg Ferrar                                                     *
  1878. * Created on: August 31, 1992                                                 *
  1879. * Modified:                                                                   *
  1880. \*****************************************************************************/
  1881.  
  1882. void remove_get_event_vbl(void)
  1883. {
  1884.         
  1885.     /* Remove the vbl task */
  1886.     VRemove ((QElemPtr)&event_call_task.the_vbl_task);
  1887.  
  1888.     /* The vbl task is no longer installed */
  1889.     vbl_installed = FALSE;
  1890.  
  1891. }    /* remove_get_event_vbl() */
  1892.  
  1893.  
  1894.  
  1895. /*****************************************************************************\
  1896. * procedure set_event_flag                                                    *
  1897. *                                                                             *
  1898. * Purpose: This is the VBL task which makes get_another_event TRUE every few  *
  1899. *          ticks.                                                             *
  1900. *                                                                             *
  1901. * Created by: Greg Ferrar                                                     *
  1902. * Created on: August 31, 1992                                                 *
  1903. * Modified:                                                                   *
  1904. \*****************************************************************************/
  1905.  
  1906. pascal void set_event_flag(void)
  1907. {
  1908.  
  1909.     /* The base address of this tasks VBL structure is now in A0.  We can use
  1910.         this to get the application’s A5 global pointer.  We need this to be
  1911.         able to access gZ80Yield */
  1912.     asm {
  1913.         move.l A5, -(SP)            ; save current A5
  1914.         move.l -8(A0), A5            ; get applications’s A5
  1915.         }
  1916.     
  1917.     get_another_event = TRUE;    /* tell rtrace to get another event */
  1918.     
  1919.     /* Start another countdown until the next time we get called */
  1920.     event_call_task.the_vbl_task.vblCount = time_between_events;
  1921.     
  1922.     asm {
  1923.         move.l (SP)+, A5        ; restore the old A5
  1924.         }
  1925.  
  1926. }    /* set_event_flag() */
  1927.  
  1928.  
  1929.  
  1930. /*****************************************************************************\
  1931. * procedure ray_trace_sff                                                     *
  1932. *                                                                             *
  1933. * Purpose: This procedure is basically the interface between the mac aspect   *
  1934. *          of this program and the unix-style aspect.  It sets up the         *
  1935. *          variables for rtrace to do its ray tracing, and then calls it.     *
  1936. *                                                                             *                                                                             *
  1937. * Created by: Greg Ferrar                                                     *
  1938. * Created on: August 22, 1992                                                 *
  1939. * Modified:                                                                   *
  1940. *   WHO          WHEN             WHAT                                        *
  1941. \*****************************************************************************/
  1942.  
  1943. void ray_trace_sff(void)
  1944.     
  1945. {
  1946.  
  1947.     params_struct    params;
  1948.     Rect            image_frame = {0, 0, 0, 0};
  1949.     short            item_hit;
  1950.     char            string[100];
  1951.     long            scene_time;
  1952.     double            tstart, tend;
  1953.     double            tstep;
  1954.     long            frame_number;
  1955.     short             error;
  1956.     char            frame_filename[50];
  1957.     volumeParam        pb;
  1958.     long            picture_size;
  1959.  
  1960.     /* If we're already rendering, prompt before we abort and start over */
  1961.     if (rendering)
  1962.         {
  1963.         
  1964.         /* Put up the Abort Rendering? alert */
  1965.         ShowWindow(abort_render_dialog);
  1966.         SelectWindow(abort_render_dialog);
  1967.         ModalDialog ((ProcPtr) NULL, &item_hit);
  1968.         HideWindow(abort_render_dialog);
  1969.  
  1970.         /* If user cancelled, don't do anything */
  1971.         if (item_hit == ABORT_RENDER_CANCEL)
  1972.             return;
  1973.         
  1974.         /* Terminate the previous render */
  1975.         post_render(FALSE);
  1976.         
  1977.         }
  1978.  
  1979.     /* Get rid of any temp files left over from last render */
  1980.     delete_temp_files(FALSE);
  1981.  
  1982.     /* Get the time when we start, so we can tell how long it took */
  1983.     total_time = TickCount();
  1984.  
  1985.     /* If we're supposed to animate, get the information from the animation dialog */
  1986.     if (GetCtlValue(animate_checkbox))
  1987.         {
  1988.         get_animation_info(&tstart, &tend, &frames);
  1989.  
  1990.         /* Find how much space a single picture takes on disk */
  1991.         picture_size = ((image_width - 1) * (image_height - 1) * 3 + 20);
  1992.     
  1993.         /* Generate an error if there's not enough space on the disk to
  1994.             store all animations */
  1995.         pb.ioVolIndex = 0;                    /* use vrefnum */
  1996.         pb.ioVRefNum = temp_folder_wd_id;    /* the directory ~~temp files go to */
  1997.         error = PBGetVInfo(&pb, FALSE);
  1998.         if (error) abortive_error(error);
  1999.  
  2000.         /* If the amount of free space isn't enough, error */
  2001.         if ((pb.ioVAlBlkSiz * pb.ioVFrBlk) < (frames * picture_size))
  2002.             abortive_string_error("Not enough disk space to generate animation.");
  2003.  
  2004.         }
  2005.  
  2006.  
  2007.     /* Show the status dialog, if we're supposed to */
  2008.     if (show_status_window_flag)
  2009.         {
  2010.         set_progress_bar_value(0);
  2011.         show_status_dialog(FALSE);
  2012.         }
  2013.         
  2014.     /* Hide the options dialog, if we're supposed to */
  2015.     if (hide_options_window_flag)
  2016.         hide_options_dialog();
  2017.         
  2018.     /* Set the prompt to "Preparing for render" */
  2019.     if (status_dialog_visible) set_status_text("\pPreparing for Render…");
  2020.     
  2021.     /* update the amount of free memory */
  2022.     update_status_free_memory();
  2023.     
  2024.     /* Get the options for this file */
  2025.     params.current_param = params.current_loc = 0;
  2026.     generate_params(¶ms);
  2027.  
  2028.     /* Add parameter which tell RTrace to save this as a pmm file */
  2029.     add_parameter (¶ms, "O1");
  2030.     
  2031.     /* Add parameters which specify input sff filename and output ppm filename */
  2032.     add_parameter (¶ms, sff_filename);
  2033.     add_parameter (¶ms, "~~rttemp.ppm");
  2034.  
  2035.     /* Make a rectangle which encloses the image */
  2036.     image_frame.right = image_width;
  2037.     image_frame.bottom = image_height;
  2038.  
  2039.     /* If we are supposed to keep an offscreen PixMap of the image, create
  2040.         it now.  If we don't have 32-bit QD, don't do it regardless. */
  2041.     if (keep_image_in_memory && f32bit_QD_available)
  2042.         {
  2043.         /* If there's already an offscreen PixMap, dispose of it */
  2044.         if (is_offscreen_port)
  2045.             dispose_offscreen_port();
  2046.         
  2047.         /* Create an offscreen CGrafPort */
  2048.         create_offscreen_grafport(&image_frame);
  2049.  
  2050.         /* Update the image data size in the status dialog */
  2051.         set_status_image_data_size(
  2052.                         GetPtrSize( ((*(image_port->portPixMap))->baseAddr)) +
  2053.                             sizeof(CGrafPort));
  2054.  
  2055.         }
  2056.     
  2057.     /* Open the image window, if preferences say so.  If we don't have color
  2058.         QuickDraw, don't do it regardless */
  2059.     if (show_image_rendering && f8bit_QD_available)
  2060.         {
  2061.  
  2062.         /* Get the title of the window */
  2063.         strcpy(string, sff_filename);
  2064.         string[strlen(string) - 4] = 0;    /* chop off .sff */
  2065.         
  2066.         /* Set the window title */
  2067.         SetWTitle (image_window, CtoPstr(string));
  2068.             
  2069.         /* Resize the Image Window to the correct size */
  2070.         SizeWindow (image_window, image_width, image_height, FALSE);
  2071.  
  2072.         /* Make the image window visible */
  2073.         show_image_window(FALSE);
  2074.         }
  2075.  
  2076.     /* disable the open and save items in the file menu */
  2077.     DisableItem(file_menu, OPEN_ITEM);
  2078.     DisableItem(file_menu, SAVE_ITEM);
  2079.     
  2080.     /* If we're faking a button click, dehilight it */
  2081.     HiliteControl(render_button_handle, 0);
  2082.  
  2083.     /* remember we are rendering */
  2084.     rendering = TRUE;
  2085.         
  2086.     /* assume that the image is complete until user cancels */
  2087.     image_complete = TRUE;
  2088.         
  2089.     /* start drawing at the top of the window */
  2090.     current_line = 0;
  2091.  
  2092.     /* Set the "maximum" number of objects and image size to the
  2093.         actual values for this scene */
  2094.     SCREEN_SIZE_X_MAX = image_width + 1;
  2095.     SCREEN_SIZE_Y_MAX = image_height + 1;
  2096.  
  2097.     /* Set variables which depend on these maximums */
  2098.     previous_repetitions = SCREEN_SIZE_X_MAX;
  2099.  
  2100.     /* If we're ever giving control to the background, install the VBL
  2101.         which will make get_another_event TRUE every time_between_events
  2102.         ticks */
  2103.     if (allow_background_tasks)
  2104.         install_get_event_vbl();
  2105.  
  2106.     /* Don't EVER get an event if we're not supposed to. */
  2107.     get_another_event = FALSE;
  2108.  
  2109.     /* Load in scene information, unless we are Rendering Again.  We Render
  2110.         Again when there is no need to read scene information, which happens
  2111.         when the scene is still in memory, and we are rendering the same file,
  2112.         and the texture mode has not changed */
  2113.     if ((!scene_in_memory) || (!rendering_same_file) || (texture_mode_changed))
  2114.         {
  2115.  
  2116.         /* Add a header to the log window */
  2117.         add_line_to_log_window ("\r");
  2118.         sprintf(string, "#### Rendering SFF file %s\r", sff_filename);
  2119.         add_line_to_log_window (string);
  2120.         add_line_to_log_window ("\r");
  2121.  
  2122.         /* Set the status string to say we're preprocessing the sff file */
  2123.         if (status_dialog_visible) set_status_text("\pPreprocessing .sff file…");
  2124.         
  2125.         /* Use twice the number of scene objects as an upper bound for the
  2126.             total possible number of objects (including cluster objects) */
  2127.         OBJECTS_MAX = 2*number_noncluster_objects + 1000;
  2128.  
  2129.         /* Set the number of objects text in the status dialog */
  2130.         set_status_num_objects(number_noncluster_objects);
  2131.  
  2132.         /* Remove all previous rtrace allocations from memory */
  2133.         free_all();
  2134.         
  2135.         /* update the free memory in the status dialog */
  2136.         update_status_free_memory();
  2137.         
  2138.         /* Allocate data structures that depend on SCREEN_SIZE_X_MAX */
  2139.         ALLOCATE(true_color, rgb_struct, SCREEN_SIZE_X_MAX);
  2140.         ALLOCATE(back_mask, real, SCREEN_SIZE_X_MAX);
  2141.  
  2142.         /* Tell ray_trace() to enclose as usual */
  2143.         do_enclose = TRUE;
  2144.  
  2145.         /* Tell rtrace the parameters */
  2146.         get_parameters(params.current_param - 1, &(params.parameters[1]));
  2147.  
  2148.         /* The files are open and haven't been closed yet */
  2149.         scene_file_open = picture_file_open = TRUE;
  2150.  
  2151.         /* Remember current time so we can later display time to read scene */
  2152.         scene_time = TickCount();
  2153.  
  2154.         /* Read in the new scene */
  2155.         get_scene();
  2156.         
  2157.         /* The scene file is now closed */
  2158.         scene_file_open = FALSE;
  2159.         
  2160.         /* Display the number of seconds it took */
  2161.         sprintf(string, "Time to read scene: %ld seconds\r",
  2162.                             (TickCount() - scene_time)/60);
  2163.         add_line_to_log_window (string);
  2164.  
  2165.         /* Remember that the scene is in memory */
  2166.         scene_in_memory = TRUE;
  2167.  
  2168.         /* Assume we are rendering the same file until user changes
  2169.             file selection */
  2170.         rendering_same_file = TRUE;
  2171.         
  2172.         /* Assume textures mode will not change until user actually
  2173.             selects a new mode from the menu */
  2174.         texture_mode_changed = FALSE;
  2175.         
  2176.         }
  2177.         
  2178.     else
  2179.         {
  2180.  
  2181.         /* Add a header to the log window */
  2182.         add_line_to_log_window ("\r");
  2183.         sprintf(string, "#### Rerendering SFF file %s\r", sff_filename);
  2184.         add_line_to_log_window (string);
  2185.         add_line_to_log_window ("\r");
  2186.  
  2187.         /* Free previous data structures that depend on SCREEN_SIZE_X_MAX */
  2188.         FREE(true_color);
  2189.         FREE(back_mask);
  2190.  
  2191.         /* Allocate data structures that depend on SCREEN_SIZE_X_MAX */
  2192.         ALLOCATE(true_color, rgb_struct, SCREEN_SIZE_X_MAX);
  2193.         ALLOCATE(back_mask, real, SCREEN_SIZE_X_MAX);
  2194.  
  2195.         /* Tell ray_trace() NOT to enclose */
  2196.         do_enclose = FALSE;
  2197.         
  2198.         /* Just tell rtrace the new parameters */
  2199.         get_parameters(params.current_param - 1, &(params.parameters[1]));
  2200.  
  2201.         /* The files are open and haven't been closed yet */
  2202.         scene_file_open = picture_file_open = TRUE;
  2203.  
  2204.         }
  2205.  
  2206.     /* If we are animating, we need to generate a bunch of images */
  2207.     if (GetCtlValue(animate_checkbox))
  2208.         {
  2209.  
  2210.         /* we don't want to use ~~rttemp.ppm after all */
  2211.         CLOSE(picture);
  2212.         picture_file_open = FALSE;
  2213.  
  2214.         frame_number = 1;
  2215.         tstep = (tend - tstart) / (frames - 1);
  2216.         for (t = tstart; t < tend*1.001; t += tstep, frame_number++)
  2217.             {
  2218.  
  2219.             /* Don't enclose after the first frame */
  2220.             if (frame_number != 1)
  2221.                 do_enclose = FALSE;
  2222.  
  2223.             /* Set up the scene for this frame */
  2224.             setup_frame();
  2225.  
  2226.             /* Open a new one with a numbered name */
  2227.             sprintf(string, "~~rttemp%ld.ppm", frame_number);
  2228.             OPEN(picture, string, WRITE_BINARY);
  2229.             picture_file_open = TRUE;
  2230.             
  2231.             /* Also update the status window to say we're rendering */
  2232.             sprintf(string, "Rendering frame %ld of %ld…", frame_number, frames);
  2233.             if (status_dialog_visible) set_status_text(CtoPstr(string));
  2234.             
  2235.             /* Generator the scene */
  2236.             ray_trace();
  2237.             
  2238.             /* The picture file is closed now */
  2239.             picture_file_open = FALSE;
  2240.             
  2241.             /* update the amount of free memory */
  2242.             update_status_free_memory();
  2243.     
  2244.             }
  2245.             
  2246.         }
  2247.  
  2248.     else
  2249.         {
  2250.         
  2251.         /* Update the status window to say we're rendering */
  2252.         if (status_dialog_visible) set_status_text("\pRendering…");
  2253.     
  2254.         /* Generate a single image */
  2255.         ray_trace();
  2256.         picture_file_open = FALSE;
  2257.  
  2258.         }
  2259.     
  2260.     /* Do post-render code */ 
  2261.     post_render(TRUE);
  2262.  
  2263.     /* Tell the user that we're done.  If there's a notification manager,
  2264.         we use it. */
  2265.     if ((in_background) && (notification_manager_available))
  2266.         {
  2267.         
  2268.         /* Set up notification to flash an icon in the menu bar */
  2269.         notification.qType = 8;                /* Notification Mgr Queue */
  2270.         notification.nmMark = 1;            /* Put diamond by appl name */
  2271.         notification.nmIcon = notification_icon;    /* flash this icon */
  2272.         notification.nmSound = NULL;        /* no sound */
  2273.         notification.nmStr = NULL;            /* no dialog */
  2274.         notification.nmResp = NULL;            /* no respose procedure */
  2275.         
  2276.         /* Install the notification */
  2277.         error = NMInstall(¬ification);
  2278.         if (!error)
  2279.             notification_installed = TRUE;
  2280.         
  2281.         }
  2282.  
  2283.     /* Remember that the image has been modified and should be saved */
  2284.     image_saved = FALSE;
  2285.  
  2286. }    /* ray_trace_sff() */
  2287.     
  2288.  
  2289.  
  2290. /*****************************************************************************\
  2291. * procedure post_render                                                       *
  2292. *                                                                             *
  2293. * Purpose: This procedure is called after the rendering is done.              *
  2294. *                                                                             *                                                                             *
  2295. * Parameter: natural: TRUE if rendering completed natually, FALSE if it was   *
  2296. *                     aborted or terminated by error.                         *                                                                             *
  2297. *                                                                             *                                                                             *
  2298. * Created by: Greg Ferrar                                                     *
  2299. * Created on: August 28, 1992                                                 *
  2300. * Modified:                                                                   *
  2301. *   Reid Judd   Oct. 26,1992   Call CopyBits() with mode==ditherCopy after    *
  2302. *                               image has rendered so that it will be         *
  2303. *                               properly dithered on non 24-bit displays.      *
  2304. \*****************************************************************************/
  2305.  
  2306. void post_render(Boolean natural)
  2307.  
  2308. {
  2309.  
  2310.     char    string[100];
  2311.  
  2312.     /* Set the status string to say we're idle */
  2313.     if (status_dialog_visible) set_status_text("\pIdle.");
  2314.  
  2315.     /* Update the free memory text */
  2316.     update_status_free_memory();
  2317.     
  2318.     /* Remove the VBL task, if any */
  2319.     if (vbl_installed)
  2320.         remove_get_event_vbl();
  2321.  
  2322.     /* Update the Render button to say "Render Again" */
  2323.     update_render_button();
  2324.  
  2325.     /* we're no longer rendering */
  2326.     rendering = FALSE;
  2327.  
  2328.     /* enable the open, close, and save items in the file menu */
  2329.     EnableItem(file_menu, OPEN_ITEM);
  2330.     EnableItem(edit_menu, PREFERENCES_ITEM);
  2331.  
  2332.     /* If there's a complete image to save or copy, enable the Save...
  2333.         and Copy... items */
  2334.     if (image_complete)
  2335.     {
  2336.         EnableItem(file_menu, SAVE_ITEM);
  2337.         EnableItem(edit_menu, COPY_ITEM);
  2338.     }
  2339.     
  2340.     /* Display the total elapsed time */
  2341.     sprintf(string, "Total time elapsed: %ld seconds\r",
  2342.                         (TickCount() - total_time)/60);
  2343.     add_line_to_log_window (string);
  2344.  
  2345.     /*  Assume that you've got a display less than 32 bits deep,
  2346.      *  the image is complete, and we're rendering to the 
  2347.      *  display.  Copy the image from the offscreen bitmap to 
  2348.      *  the display one more time using ditherCopy mode.
  2349.      */        
  2350.     if ( (display_depth < 32) && (image_complete) && 
  2351.          (keep_image_in_memory) && (is_offscreen_port) )
  2352.     {
  2353.       CGrafPtr     save_port;
  2354.       Rect srcRect, dstRect;
  2355.  
  2356.       /* Save the current port */
  2357.       GetPort (&save_port);
  2358.  
  2359.       /* Set the grafport to the image_port */
  2360.         SetPort (image_window);
  2361.         
  2362.         srcRect = (**(*image_port).portPixMap).bounds;
  2363.       dstRect = (*image_window).portRect;
  2364.               
  2365.         /* copy the offscreen pixmap to the window */
  2366.         
  2367.         if ( LockPixels( (*image_port).portPixMap ))
  2368.         {
  2369.         CopyBits (&((GrafPtr) image_port)->portBits,
  2370.                 &((GrafPtr) image_window)->portBits,
  2371.                 &(image_port->portRect), &(image_port->portRect),
  2372.                 ditherCopy, NULL );
  2373.         }
  2374.        UnlockPixels( (*image_port).portPixMap );
  2375.                          
  2376.       /* Restore the grafport to whatever it was before */
  2377.         SetPort (save_port);         
  2378.     }
  2379.  
  2380.     /* Set the progress bars to zero */
  2381.     set_progress_bar_value(0);
  2382.     set_sub_progress_bar_value(0);
  2383.  
  2384.     /* Close files if they were left open */
  2385.     if (picture_file_open)
  2386.         CLOSE(picture);
  2387.     if (scene_file_open)
  2388.         CLOSE(scene);
  2389.  
  2390. }    /* post_render() */
  2391.  
  2392.  
  2393. /*****************************************************************************\
  2394. * procedure create_offscreen_grafport                                         *
  2395. *                                                                             *
  2396. * Purpose: This procedure creates an offscreen grafport which will be used to *
  2397. *          keep the ray-traces image.                                         *
  2398. *                                                                             *                                                                             *
  2399. * Parameters: bounds_rect: the size of the desired bitmap.                    *                                                                             *
  2400. *                                                                             *                                                                             *
  2401. * Created by: Greg Ferrar                                                     *
  2402. * Created on: August 24, 1992                                                 *
  2403. * Modified:                                                                   *
  2404. \*****************************************************************************/
  2405.  
  2406. void create_offscreen_grafport(Rect *bounds_rect)
  2407. {
  2408.  
  2409.     CGrafPtr         temp_port;
  2410.     PixMapHandle    pixmap;
  2411.     short            error;
  2412.     RGBColor        rgb_color;
  2413.     
  2414.     /* Save the current grafPort */
  2415.     GetPort(&temp_port);
  2416.     
  2417.     /* Open the new port */
  2418.     OpenCPort (image_port);
  2419.     
  2420.     /* Get a pointer to the pixel map */
  2421.     pixmap = image_port->portPixMap;
  2422.     
  2423.     /* create a bitmap of the desired size */
  2424.     image_port->portRect = *bounds_rect;
  2425.     (*pixmap)->bounds = *bounds_rect;
  2426.     RectRgn(image_port->clipRgn, bounds_rect);
  2427.     RectRgn(image_port->visRgn, bounds_rect);
  2428.     
  2429.     /* Set the the pixmap to display direct 32-bit color */
  2430.     (*pixmap)->pixelType = RGBDirect;
  2431.     (*pixmap)->pixelSize = 32;
  2432.     (*pixmap)->cmpCount = 3;
  2433.     (*pixmap)->cmpSize = 8;
  2434.     
  2435.     /* set the number of rows to the number of pixels per row * 4 */
  2436.     (*pixmap)->rowBytes = (bounds_rect->right - bounds_rect->left) * 4;
  2437.     
  2438.     /* allocate space for the bitmap */
  2439.     (*pixmap)->baseAddr = NewPtr ((*pixmap)->rowBytes *
  2440.                                 (long) (bounds_rect->bottom - bounds_rect->top) );
  2441.     
  2442.     /* Check for out of memory error */
  2443.     if (MemError() != noErr)
  2444.         {
  2445.         /* releases memory used by CPort */
  2446.         CloseCPort(image_port);
  2447.         
  2448.         /* report error, and abort */
  2449.         abortive_string_error("Sorry, there is not enough memory to allocate the offscreen bitmap.");
  2450.         }
  2451.  
  2452.     /* Set the 15th bit of rowBytes, so this is a PixMap */
  2453.     (*pixmap)->rowBytes |= 32768;
  2454.  
  2455.     /* Set the foreground color to black and the background color to white */
  2456.     SetPort (image_port);
  2457.     rgb_color.red = rgb_color.green = rgb_color.blue = 0xFFFF;
  2458.     RGBBackColor (&rgb_color);
  2459.     rgb_color.red = rgb_color.green = rgb_color.blue = 0x0000;
  2460.     RGBForeColor (&rgb_color);
  2461.  
  2462.     /* Clear the bitmap to white */
  2463.     EraseRect(bounds_rect);
  2464.     InvertRect(bounds_rect);
  2465.     
  2466.     /* Remember that there is an offscreen port */
  2467.     is_offscreen_port = TRUE;
  2468.  
  2469.     /* Restore the port */
  2470.     SetPort(temp_port);
  2471.  
  2472. }    /*    create_offscreen_grafport()    */
  2473.  
  2474.  
  2475. /*****************************************************************************\
  2476. * procedure dispose_offscreen_port                                            *
  2477. *                                                                             *
  2478. * Purpose: This procedure gets rid of the offscreen grafport created by       *
  2479. *          create_offscreen_grafport.                                         *
  2480. *                                                                             *                                                                             *
  2481. * Created by: Greg Ferrar                                                     *
  2482. * Created on: August 24, 1992                                                 *
  2483. * Modified:                                                                   *
  2484. \*****************************************************************************/
  2485.  
  2486. void dispose_offscreen_port (void)
  2487. {
  2488.  
  2489.     /* Only dispose it if it exists */
  2490.     if (is_offscreen_port);
  2491.         {
  2492.         /* free the memory the bitmap used */
  2493.         DisposPtr ((*(image_port->portPixMap))->baseAddr);
  2494.  
  2495.         /* close the port */
  2496.         ClosePort (image_port);
  2497.     
  2498.         /* There's no longer an offscreen port */
  2499.         is_offscreen_port = FALSE;
  2500.         }
  2501.         
  2502. }    /* dispose_offscreen_port() */
  2503.